﻿using Sgr.Domain.Entities.Auditing;
using Sgr.Domain.Entities;
using Sgr.DataCategories.Domain.AdministrativeDivisions;
using Sgr.Exceptions;
using System.Reflection.Emit;

namespace Sgr.DataCategories.Domain.DataCategoryItem
{
    /// <summary>
    /// 数据字典项
    /// </summary>
    public class DataCategoryItem : CreationAndModifyAuditedEntity<long, long>, IAggregateRoot, IOptimisticLock, ITreeNode<long>
    {
        /// <summary>
        /// 无参构造函数，供ORM框架使用
        /// </summary>
        private DataCategoryItem()
        {
            State = EntityStates.Normal;
        }

        /// <summary>
        /// 创建数据字典项
        /// </summary>
        /// <param name="categoryTypeCode">字典分类编码</param>
        /// <param name="name">字典项名称</param>
        /// <param name="value">字典项值</param>
        /// <param name="isEditable">是否可编辑</param>
        /// <param name="orderNumber">排序号</param>
        /// <param name="remarks">备注</param>
        public DataCategoryItem(
            string categoryTypeCode,
            string name,
            string value,
            bool isEditable = true,
            int orderNumber = 0,
            string? remarks = null)
        {
            ValidateCategoryTypeCode(categoryTypeCode);
            ValidateName(name);
            ValidateValue(value);

            CategoryTypeCode = categoryTypeCode;
            DcItemName = name;
            DcItemValue = value;
            IsEditable = isEditable;
            OrderNumber = orderNumber;
            Remarks = remarks;
            State = EntityStates.Normal;

            // 默认为根节点
            ParentId = 0;
        }

        #region 属性

        /// <summary>
        /// 字典分类标识
        /// </summary>
        public string CategoryTypeCode { get; private set; } = string.Empty;

        /// <summary>
        /// 字典项名称
        /// </summary>
        public string DcItemName { get; private set; } = string.Empty;

        /// <summary>
        /// 字典项值
        /// </summary>
        public string DcItemValue { get; private set; } = string.Empty;

        /// <summary>
        /// 备注
        /// </summary>
        public string? Remarks { get; set; }

        /// <summary>
        /// 是否可编辑
        /// </summary>
        public bool IsEditable { get; private set; } = true;

        /// <summary>
        /// 排序号
        /// </summary>
        public int OrderNumber { get; set; } = 0;

        /// <summary>
        /// 状态
        /// </summary>
        public EntityStates State { get; private set; } = EntityStates.Normal;

        #endregion 属性

        #region 状态管理

        /// <summary>
        /// 修改状态
        /// </summary>
        /// <param name="state">状态</param>
        public void ChangeState(EntityStates state)
        {
            if (State != state)
            {
                State = state;
            }
        }

        /// <summary>
        /// 标记删除
        /// </summary>
        public void MarkForDeletion()
        {
            if (!IsEditable)
                throw DomainException.ValidationError("系统预置的数据字典项不允许删除");

            State = EntityStates.Deactivate;
        }

        /// <summary>
        /// 恢复启用
        /// </summary>
        public void Restore()
        {
            if (State == EntityStates.Deactivate)
            {
                State = EntityStates.Normal;
            }
        }

        #endregion 状态管理

        #region 业务方法

        /// <summary>
        /// 更新基本信息
        /// </summary>
        /// <param name="name">名称</param>
        /// <param name="remarks">备注</param>
        /// <param name="orderNumber">排序号</param>
        /// <exception cref="BusinessException">不可编辑时抛出异常</exception>
        public void UpdateBasicInfo(
            string name,
            string? remarks = null,
            int? orderNumber = null)
        {
            if (!IsEditable)
                throw DomainException.ValidationError("系统预置的数据字典项不允许修改");

            ValidateName(name);

            DcItemName = name;
            Remarks = remarks;

            if (orderNumber.HasValue)
                OrderNumber = orderNumber.Value;
        }

        /// <summary>
        /// 修改字典项值
        /// </summary>
        /// <param name="value">值</param>
        /// <exception cref="BusinessException">不可编辑时抛出异常</exception>
        public void ChangeValue(string value)
        {
            if (!IsEditable)
                throw DomainException.ValidationError("系统预置的数据字典项不允许修改值");

            ValidateValue(value);

            if (DcItemValue != value)
            {
                DcItemValue = value;
            }
        }

        /// <summary>
        /// 改变父
        /// </summary>
        /// <param name="parentId"></param>
        /// <param name="nodePath"></param>
        internal void SetParent(long parentId, string nodePath)
        {
            if (ParentId != parentId)
            {
                this.ParentId = parentId;
            }
            this.NodePath = nodePath;
        }

        #endregion 业务方法

        #region 验证方法

        /// <summary>
        /// 验证字典分类编码
        /// </summary>
        /// <param name="categoryTypeCode">字典分类编码</param>
        /// <exception cref="BusinessException">验证失败时抛出</exception>
        private static void ValidateCategoryTypeCode(string categoryTypeCode)
        {
            if (string.IsNullOrWhiteSpace(categoryTypeCode))
                throw DomainException.ValidationError("字典分类编码不能为空");

            if (categoryTypeCode.Length > 50)
                throw DomainException.ValidationError("字典分类编码长度不能超过50个字符");
        }

        /// <summary>
        /// 验证名称
        /// </summary>
        /// <param name="name">名称</param>
        /// <exception cref="BusinessException">验证失败时抛出</exception>
        private static void ValidateName(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                throw DomainException.ValidationError("字典名称不能为空");

            if (name.Length > 100)
                throw DomainException.ValidationError("字典名称长度不能超过100个字符");
        }

        /// <summary>
        /// 验证字典项值
        /// </summary>
        /// <param name="value">值</param>
        /// <exception cref="BusinessException">验证失败时抛出</exception>
        private static void ValidateValue(string value)
        {
            if (string.IsNullOrWhiteSpace(value))
                throw DomainException.ValidationError("字典编码不能为空");

            if (value.Length > 100)
                throw DomainException.ValidationError("字典编码长度不能超过100个字符");
        }

        #endregion 验证方法

        #region ITreeNode (树形结构)

        /// <summary>
        /// 上级节点Id
        /// </summary>
        public long ParentId { get; private set; } = 0;

        /// <summary>
        /// 树节点层次目录
        /// </summary>
        public string NodePath { get; private set; } = string.Empty;

        #endregion ITreeNode (树形结构)

        #region IOptimisticLock (乐观锁)

        /// <summary>
        /// 行版本
        /// </summary>
        public long RowVersion { get; set; }

        #endregion IOptimisticLock (乐观锁)
    }
}